Skip to content

fix(child-session): dynamically exclude blocked package tools from child inheritance (#483) - #494

Open
naivezip wants to merge 1 commit into
openpi-dev:mainfrom
naivezip:develop
Open

fix(child-session): dynamically exclude blocked package tools from child inheritance (#483)#494
naivezip wants to merge 1 commit into
openpi-dev:mainfrom
naivezip:develop

Conversation

@naivezip

@naivezip naivezip commented Sep 8, 2026

Copy link
Copy Markdown

Problem

Fixes #483. Also addresses the preflight root cause reported in #493.

When @tt-a1i/openpi is co-installed with third-party extensions such as pi-intercom, subagent_spawn (including standard subagents without explicit agent_type) and Workflow child sessions fail during startup preflight before the first model turn:

Child tool preflight failed: requested tool "intercom" is unavailable after child extensions initialized. Check the Agent Type tools list and child extension loading.

Root cause:
blockedPackageSources() strips pi-intercom from child session extensions/packages to avoid cross-wiring session identity (per #128). However, during child tool allowlist resolution, inheritedChildToolAllowlist(pi.getActiveTools(), roleTools) blindly inherited all active parent tools unless they were explicitly listed in OpenPI's internal CHILD_EXCLUDED_TOOL_NAMES. Because foreign tools like intercom do not belong in OpenPI's internal tool surface (and adding them there violates the bidirectional fail-closed drift guard), tools from blocked packages leaked into the child requested tool list where they could never be satisfied.

Value

  • Restores clean subagent delegation and workflow execution when third-party packages like pi-intercom are present in the parent environment.
  • Provides a structural alignment fix rather than hardcoding foreign tool names in OpenPI internal tool lists.
  • Dynamically respects package blocking boundaries established in #128 without breaking the bidirectional drift guard or requiring ongoing manual maintenance of third-party tool names.

Approach

  1. Dynamic Tool Provenance Filtering in child-session.ts:
    • Keep CHILD_EXCLUDED_TOOL_NAMES strictly scoped to OpenPI-owned parent tools, preserving the bidirectional partition invariant (CHILD_SAFE_PACKAGE_TOOL_NAMES + CHILD_EXCLUDED_TOOL_NAMES == OPENPI_TOOL_SURFACE_NAMES).
    • Add ChildToolInheritanceOptions ({ availableTools?: readonly PiToolDescriptor[]; cwd?: string }) and isBlockedChildTool(tool, options) to inspect tool provenance (tool.sourceInfo) against blocked child package matchers (createPiIntercomPackageMatcher).
    • In inheritedChildToolAllowlist, if available tool descriptors are provided, dynamically drop any tools originating from blocked child packages.
  2. Plumb Available Tools at Caller Seams:
    • In extensions/subagents/index.ts, pass { availableTools: pi.getAllTools?.(), cwd: ctx.cwd } into inheritedChildToolAllowlist.
    • In extensions/workflows/index.ts, pass { availableTools: pi.getAllTools?.(), cwd: ctx.cwd } into inheritedChildToolAllowlist.
  3. Drift Guard & Regression Testing:
    • Retain the untouched, fail-closed bidirectional drift guard in tests/extensions/shared/child-session.test.ts.
    • Add regression test asserting that tools from blocked packages (like intercom from pi-intercom) are dynamically excluded during inheritance and allow child sessions to pass preflight.
    • Revert any foreign tool workarounds from tests/extensions/shared/tool-surface.test.ts and tests/extensions/subagents/agent-types.test.ts.

Validation

  • node --test --experimental-strip-types tests/extensions/shared/child-session.test.ts: 20/20 passed
  • node --test --experimental-strip-types tests/extensions/shared/tool-surface.test.ts: 9/9 passed
  • node --test --experimental-strip-types tests/extensions/subagents/agent-types.test.ts: 22/22 passed
  • node --test --experimental-strip-types tests/extensions/subagents/index.test.ts: 16/16 passed
  • node --test --experimental-strip-types tests/extensions/subagents/pi-backend.test.ts: 5/5 passed
  • node --test --experimental-strip-types tests/extensions/workflows/runner.test.ts: 26/26 passed
  • node scripts/check-config-contract.mjs: 15/15 fields passed
  • node scripts/check-discipline-ledger.mjs: 12/12 rows passed
  • npx biome format & npx biome lint --error-on-warnings: Clean, 0 errors
  • git diff upstream/main..HEAD: Exactly 4 files changed (+183, -1)

Impact

  • User-visible behavior: Subagents and workflows start cleanly when pi-intercom is co-installed in the parent.
  • Model-visible context/tools: Tools from blocked child packages are omitted from child session tool allowlists.
  • Runtime/lifecycle: Preserves child isolation invariants from setup: 移除 OpenPI 对 pi-intercom 的主动安装与配置职责 #128 fail-closed.
  • Persistence/configuration: No configuration schema changes.
  • Compatibility & risks: Low risk; structural alignment between package filtering and tool inheritance boundaries.

@github-actions github-actions Bot added the area:subagents Subagent delegation, skills, or tests label Sep 8, 2026
@github-actions github-actions Bot added the area:workflows Workflow engine, capability, skills, or tests label Sep 9, 2026
@naivezip naivezip changed the title fix(child-session): exclude intercom from child tool allowlist (#483) fix(child-session): dynamically exclude blocked package tools from child inheritance (#483) Sep 9, 2026
…ild inheritance (openpi-dev#483)

pi-intercom is excluded from child sessions via blockedPackageSources to prevent concurrent process.env session cross-wiring (openpi-dev#128). However, when pi-intercom was active in the parent session, inheritedChildToolAllowlist projected its tools into child sessions, causing subagent_spawn and workflow child sessions to fail preflight checks.

Rather than hardcoding foreign tool names into OpenPI's CHILD_EXCLUDED_TOOL_NAMES (which is strictly reserved for OpenPI-owned parent-only tools and enforced by the fail-closed drift guard), dynamically drop tools from blocked packages during child inheritance:

- Inspect tool.sourceInfo in inheritedChildToolAllowlist against blocked child package matchers
- Pass pi.getAllTools() and cwd context from subagents/index.ts and workflows/index.ts
- Preserve CHILD_EXCLUDED_TOOL_NAMES and bidirectional drift guards strictly for OpenPI tools
- Add regression coverage verifying dynamic exclusion of tools from blocked packages while preserving ordinary tools and passing child preflight

@tt-a1i tt-a1i left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at exact head 88531a1.

Standards

[P1] Unverifiable tool provenance currently fails open. The new local descriptor makes sourceInfo and availableTools optional, and isBlockedChildTool() returns false when package identity inspection throws. A blocked-package tool with missing or unreadable provenance is therefore treated as child-safe. Pi 0.85.1 provides getAllTools() with sourceInfo; please use that authoritative type non-optionally and deny/throw when non-builtin provenance cannot be verified.

[P2] Blocked package identity is implemented twice with different conditions: blockedPackageSources() filters canonical resources, while isBlockedChildTool() independently hardcodes pi-intercom matching and ignores origin. Extract one shared blocked-package identity policy for both projections.

Spec

[P2] The regression covers a helper and synthetic preflight only. It does not execute Direct spawn, typed spawn, or Workflow callers with a real local/npm/git pi-intercom fixture, so omission or caller-plumbing drift would go undetected. Because this changes the child model-visible authority boundary, please add caller-level Direct and Workflow tests.

[P3] The array shorthand and unused agentDir generality are outside the required production path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:subagents Subagent delegation, skills, or tests area:workflows Workflow engine, capability, skills, or tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(child-session): pi-intercom 同装时 subagent_spawn 预检必挂——intercom 未进 CHILD_EXCLUDED_TOOL_NAMES

2 participants